#include "ExpAST.h"
#include <iostream>
using std::cout;
using std::endl;
void ExpAST::Dump() const
{
    this->content->Calc();
}

int ExpAST::Calc() const
{
    return this->content->Calc();
}

bool ExpAST::is_const() const
{
    return this->content->Calc();
}

void PrimaryAST::Dump() const
{
    this->content->Dump();
}

int PrimaryAST::Calc() const
{
    return this->content->Calc();
}

bool PrimaryAST::is_const() const
{
    return this->content->is_const();
}

void NumberAST::Dump() const
{
    cout << "{\"type\":\"Number\",\"content\":" << this->content << "}";
}

int NumberAST::Calc() const
{
    return this->content;
}

bool NumberAST::is_const() const
{
    return true;
}

void UnaryAST::Dump() const
{
    cout << "{\"type\":\"Unary\",\"op\":\"";
    switch (this->op)
    {
    case POS:
        cout << "+";
        break;
    case NEG:
        cout << "-";
        break;
    case NOT:
        cout << "!";
        break;
    default:break;
    }
    cout << "\",\"content\":";
    this->content->Dump();
    cout << "}";
}

int UnaryAST::Calc() const
{
    switch (this->op)
    {
    case NEG:
        return -this->content->Calc();
    case NOT:
        return this->content->Calc() != 0;
    default:
        return this->content->Calc();
    }
    return 0;
}

bool UnaryAST::is_const() const
{
    return this->content->is_const();
}

void MulAST::Dump() const
{
    cout << "{\"type\":\"Mul\",\"op\":\"";
    switch (this->op)
    {
    case MUL:
        cout << "*";
        break;
    case DIV:
        cout << "/";
        break;
    case MOD:
        cout << "%";
        break;
    default:break;
    }
    cout << "\",";
    if (this->op == DEFAULT)
    {
        cout << "\"content\":";
        this->exp1->Dump();
    }
    else
    {
        cout << "\"exp1\":";
        this->exp1->Dump();
        cout << ",\"exp2\":";
        this->exp2->Dump();
    }
    cout << "}";
}


int MulAST::Calc() const
{
    switch (this->op)
    {
    case MUL:
        return this->exp1->Calc() * this->exp2->Calc();
    case DIV:
        return this->exp1->Calc() / this->exp2->Calc();
    case MOD:
        return this->exp1->Calc() % this->exp2->Calc();
    default:
        return this->exp1->Calc();
    }
    return 0;
}

bool MulAST::is_const() const
{
    return (this->op == DEFAULT) ? this->exp1->is_const() : (this->exp1->is_const() && this->exp2->is_const());
}


void AddAST::Dump() const
{
    cout << "{\"type\":\"Add\",\"op\":\"";
    switch (this->op)
    {
    case ADD:
        cout << "+";
        break;
    case SUB:
        cout << "-";
        break;
    default:break;
    }
    cout << "\"";
    if (this->op == DEFAULT)
    {
        cout << "\"content\":";
        this->exp1->Dump();
    }
    else
    {
        cout << "\"exp1\":";
        this->exp1->Dump();
        cout << "\"exp2\":";
        this->exp2->Dump();
    }
    cout << "}";
}


int AddAST::Calc() const
{
    switch (this->op)
    {
    case ADD:
        return this->exp1->Calc() + this->exp2->Calc();
    case SUB:
        return this->exp1->Calc() - this->exp2->Calc();
    default:
        return this->exp1->Calc();
    }
    return 0;
}

bool AddAST::is_const() const
{
    return (this->op == DEFAULT) ? this->exp1->is_const() : (this->exp1->is_const() && this->exp2->is_const());
}


void RelAST::Dump() const
{
    cout << "{\"type\":\"Rel\",\"op\":\"";
    switch (this->op)
    {
    case GT:
        cout << ">";
        break;
    case GE:
        cout << ">=";
        break;
    case LT:
        cout << "<";
        break;
    case LE:
        cout << "<=";
        break;
    default:break;
    }
    cout << "\"";
    if (this->op == DEFAULT)
    {
        cout << "\"content\":";
        this->exp1->Dump();
    }
    else
    {
        cout << "\"exp1\":";
        this->exp1->Dump();
        cout << "\"exp2\":";
        this->exp2->Dump();
    }
    cout << "}";
}


int RelAST::Calc() const
{
    switch (this->op)
    {
    case GT:
        return this->exp1->Calc() > this->exp2->Calc();
    case GE:
        return this->exp1->Calc() >= this->exp2->Calc();
    case LT:
        return this->exp1->Calc() < this->exp2->Calc();
    case LE:
        return this->exp1->Calc() <= this->exp2->Calc();
    default:
        return this->exp1->Calc();
    }
    return 0;
}

bool RelAST::is_const() const
{
    return (this->op == DEFAULT) ? this->exp1->is_const() : (this->exp1->is_const() && this->exp2->is_const());
}

void EqAST::Dump() const
{
    cout << "{\"type\":\"Eq\",\"op\":\"";
    switch (this->op)
    {
    case EQ:
        cout << "==";
        break;
    case NE:
        cout << "!=";
        break;
    default:break;
    }
    cout << "\"";
    if (this->op == DEFAULT)
    {
        cout << "\"content\":";
        this->exp1->Dump();
    }
    else
    {
        cout << "\"exp1\":";
        this->exp1->Dump();
        cout << "\"exp2\":";
        this->exp2->Dump();
    }
    cout << "}";
}


int EqAST::Calc() const
{
    switch (this->op)
    {
    case EQ:
        return this->exp1->Calc() == this->exp2->Calc();
    case NE:
        return this->exp1->Calc() != this->exp2->Calc();
    default:
        return this->exp1->Calc();
    }
    return 0;
}

bool EqAST::is_const() const
{
    return (this->op == DEFAULT) ? this->exp1->is_const() : (this->exp1->is_const() && this->exp2->is_const());
}

void LAndAST::Dump() const
{
    cout << "{\"type\":\"LAnd\",\"op\":\"";
    switch (this->op)
    {
    case true:
        cout << "&&";
        break;
    default:break;
    }
    cout << "\"";
    if (this->op == false)
    {
        cout << "\"content\":";
        this->exp1->Dump();
    }
    else
    {
        cout << "\"exp1\":";
        this->exp1->Dump();
        cout << "\"exp2\":";
        this->exp2->Dump();
    }
    cout << "}";
}


int LAndAST::Calc() const
{
    switch (this->op)
    {
    case true:
        return (this->exp1->Calc() != 0) && (this->exp2->Calc() != 0);
    default:
        return this->exp1->Calc();
    }
    return 0;
}

bool LAndAST::is_const() const
{
    return (this->op == false) ? this->exp1->is_const() : (this->exp1->is_const() && this->exp2->is_const());
}

void LOrAST::Dump() const
{
    cout << "{\"type\":\"LOr\",\"op\":\"";
    switch (this->op)
    {
    case true:
        cout << "||";
        break;
    default:break;
    }
    cout << "\"";
    if (this->op == false)
    {
        cout << "\"content\":";
        this->exp1->Dump();
    }
    else
    {
        cout << "\"exp1\":";
        this->exp1->Dump();
        cout << "\"exp2\":";
        this->exp2->Dump();
    }
    cout << "}";
}


int LOrAST::Calc() const
{
    switch (this->op)
    {
    case true:
        return (this->exp1->Calc() != 0) || (this->exp2->Calc() != 0);
    default:
        return this->exp1->Calc();
    }
    return 0;
}

bool LOrAST::is_const() const
{
    return (this->op == false) ? this->exp1->is_const() : (this->exp1->is_const() && this->exp2->is_const());
}